import {Injectable} from "@nestjs/common";
import {Neo4jDao} from "../common/database/neo4j.dao";
import {Cron} from "@nestjs/schedule";
import {RedisService} from "../common/database/redis/redis.service";
import {BOOK} from "../../common/constants/neo4jNode";
import {HOTBOOK} from "../../common/constants/redisKey";
import {UserActionService} from "../common/userAction/userAction.service";
import {UserActionDocument} from "../common/userAction/userAction.schema";
import {UserActions} from "../../common/enums/userActions";

/**
 * @Description: 离线调度模块
 * @author zhaojiuyi
 * @date 2023/4/19
 */

@Injectable()
export class RecommendOfflineService {

    constructor(
        private readonly neo4jDao: Neo4jDao,
        private readonly redisService: RedisService,
        private readonly userActionService: UserActionService
    ) {
        /* 系统运行时先执行一次 */
        this.calculationBookHot()
    }

    /**
     * @Description: 定时任务(每小时一次)，计算图书热度排行榜（根据图书被用户阅读的次数）
     * @author zhaojiuyi
     * @date 2023/4/19
     */
    @Cron("0 0 * * * *")
    async calculationBookHot() {
        const size = 5000 // 保存前5000条数据
        // const CQL = `MATCH (b:${BOOK})<-[r:${HAVE_READ}]-(u:${USER})
        // WITH b, COUNT(r) as readCount RETURN b,
        // readCount ORDER BY readCount DESC limit ${size}`
        // const result = await this.neo4jDao.read(CQL, "b")
        const historyBookList: UserActionDocument[] = await this.userActionService.findSort({action: UserActions.HAS_READ}, size)
        const bookHotMap = new Map<string, number>()
        for (const book of historyBookList) {
            const {bookId} = book
            const num: number = bookHotMap.get(bookId)
            bookHotMap.set(bookId, num ? num + 1 : 1)
        }
        /* 将map对象转换为元组 */
        const bookHotList: [string, number][] = [...bookHotMap.entries()].sort((a, b) => b[1] - a[1])
        const resultList = []
        for (const [bookId] of bookHotList) {
            const book = await this.neo4jDao.findNode(BOOK, {
                id: bookId
            });
            resultList.push(book[0])
        }
        await this.redisService.setValue(HOTBOOK, resultList)
    }

    async getHotBook(size: number) {
        const result = await this.redisService.getValue(HOTBOOK)
        return <[]>result.slice(0, size)
    }

}
